/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef _NCI_TRANSPORT_H_
#define _NCI_TRANSPORT_H_

/**
 * 定义NCI传输层API接口
*/

#include "nci_types.h"
#include "nfc_transport_api.h"
#include "nfc_osi_api.h"
#include "priority_queue.h"

#define NCI_BUF_HEAD_SIZE 3
#define NCI_BUF_PAYLOAD_DEFAULT_SIZE 0xFF

/**
 * @brief NCI消息头
 *
 * @note 此结构体适配小端模式，即低地址存放低字节，因此结构体中gid、pbf、mt的顺序是反的
*/
typedef struct {
    /** @brief NCI头部指针 */
    uint8_t hdr[0];
    /** @brief NCI GID */
    uint8_t gid : 4;
    /** @brief NCI PBF */
    uint8_t pbf : 1;
    /** @brief NCI MT */
    uint8_t mt : 3;
    /** @brief NCI OID */
    uint8_t oid : 6;
    /** @brief RFU 2bit预留空间 */
    uint8_t rfu_l: 1;
    uint8_t rfu_h: 1;
} tNCI_HEAD;

/**
 * @brief NCI消息
 *
 * @note 对应一条完整的NCI消息，包括头、长度、负载
 * @note 此结构体大小固定为 2+1+0xFF = 258字节
*/
typedef struct {
    /** @brief 指向NCI消息一个字节 */
    uint8_t hdr[0];
    /** @brief NCI消息头部 */
    tNCI_HEAD head;
    /** @brief NCI Payload 使用的实际长度 */
    uint8_t len;
    /** @brief NCI Payload数组 */
    uint8_t payload[NCI_BUF_PAYLOAD_DEFAULT_SIZE];
} tNCI_MESSAGE;

/**
 * @brief NCI BUF用于承载NCI消息，支持扩容
 *
 * @note 相关的操作函数在nci_utils.h中定义
 * @note 其data区域只用于存储NCI Payload，不包括NCI消息头
 * @note data指针会随着扩容而变化，不要尝试保存data指针
*/
typedef struct {
    /** @brief data指针指向的内存容量 */
    uint16_t cap;
    /** @brief data指针指向的内存实际使用的大小 */
    uint16_t len;
    /** @brief 所对应的NCI消息头 */
    tNCI_HEAD head;
    /** @brief 指向的内存就是实际存储的数据 */
    uint8_t *data;
} tNCI_BUF;

/**
 * @brief NCI等待结构体, 用于保存等待NCI消息的特征和接收buf
*/
typedef struct {
    /** @brief 目标NCI消息头部特征 */
    tNCI_HEAD head;
    /** @brief 此buf用于接收NCI消息 */
    tNCI_BUF *buf;
    /** @brief 标识是否有接收到等待的NCI消息 */
    bool is_received;
    /** @brief 用于保存在等待队列中的队列ID */
    tQUEUE_ID queue_id;
    /** @brief 如果等待的消息是RSP，则保存下rsp的状态 */
    uint8_t rsp_status;
    /** @brief 如果成功等待到此BUF，则返回此状态 */
    tNCI_STATUS matched_status;
} tNCI_WAIT_BUF;

#define SET_WAIT_BUF(_wait_buf, _head, _status, _nci_buf) { \
    (_wait_buf).head.mt = ((_head) & 0xE000) >> 13; \
    (_wait_buf).head.pbf = ((_head) & 0x1000) >> 9; \
    (_wait_buf).head.gid = ((_head) & 0x0F00) >> 8; \
    (_wait_buf).head.oid = ((_head) & 0x003F); \
    (_wait_buf).matched_status = (_status); \
    (_wait_buf).buf = (_nci_buf); \
}
/**
 * @brief NCI RSP回调函数,此回调函数是在发送完CMD并且拿到RSP后被调用，用与判断后续如何等待NTF
 *
 * @param[in] cmd 发送的NCI指令头
 * @param[in] rsp 接收到的NCI RSP
 * @param[in] p_nfc_wait_list NTF等待列表
 * @param[in] ntf_wait_list_size NTF等待列表大小
 * @param[out] p_return_status 如果返回true，返回NTF等待的状态
 * @return 如果不需要继续等待NTF返回true，否则返回false
 */
typedef bool(*tNCI_NTF_WAIT_CBACK)(tNCI_HEAD cmd, tNCI_BUF *rsp, tNCI_WAIT_BUF *p_nfc_wait_list, uint8_t ntf_wait_list_size, tNCI_STATUS *p_return_status);

/**
 * @brief DATA通道数据回调函数
 *
 * @param conn_id 数据通道ID
 * @param data 接收到的数据
 * @param data_len 数据长度
 */
typedef void(*tNCI_DATA_CBACK)(uint8_t conn_id, const uint8_t *data, uint16_t data_len);

/**
 * @brief NCI数据通道
*/
typedef struct {
    /** @brief 通道ID */
    uint8_t conn_id;
    /** @brief 通道当前的流量 */
    uint8_t credit;
    /** @brief 通道单包支持的最大payload长度 */
    uint8_t max_data_packet_payload_size;
    /** @brief 通道锁，用于控制多线程同时访问此通道 */
    tMUTEX mutex;
    /** @brief 通道的等待buf */
    tNCI_WAIT_BUF *wait_buf;
    /** @brief 通道的数据回调 */
    tNCI_DATA_CBACK cback;
} tNCI_DATA_CHANNEL;

/**
 * @brief 发送NCI指令，并且等待其指令的RSP，但是不获取RSP的值
 * 等同于调用send_nci_get_rsp_ntf(cmd, NULL, NULL, false, NCI_DEFAULT_WAIT_TIME);
 *
 * @param cmd 需要发送的NCI指令
 * @return NCI_STATUS_OK: 发送成功且获取到RSP
 *         NCI_STATUS_EXT_CMD_SEND_FAILED: 发送失败
 *         NCI_STATUS_EXT_WAIT_RSP_TIMEOUT: 等待RSP超时
 *         其他错误码: 其他错误
*/
tNCI_STATUS nci_tp_send_nci(tNCI_BUF *cmd);

/**
 * @brief 发送NCI指令，并且等待其指令的RSP和NTF
 *
 * @param cmd 需要发送的NCI指令
 * @param rsp 用于保存RSP数据的指针，如果不需要保存，则置为NULL
 * @param ntf 用于保存NTF数据的指针，如果不需要保存，则置为NULL
 * @param wait_ntf 是否需要等待NTF，如果不需要，则置为false
 * @param timeout 等待超时时间
 * @return NCI_STATUS_OK: 发送成功且获取到RSP
 *         NCI_STATUS_EXT_CMD_SEND_FAILED: 发送失败
 *         NCI_STATUS_EXT_WAIT_RSP_TIMEOUT: 等待RSP超时
 *         NCI_STATUS_EXT_WAIT_NTF_TIMEOUT: 等待NTF超时
 *         其他错误码: 其他错误
*/
tNCI_STATUS nci_tp_send_nci_get_rsp_ntf(tNCI_BUF *cmd, tNCI_BUF *rsp, tNCI_BUF *ntf, bool wait_ntf, uint32_t timeout);

/**
 * @brief 发送NCI指令，并且等待其指令的RSP，可以自定义如何等待NTF
 *
 * @param[in] cmd 需要发送的NCI指令
 * @param[out] rsp 用于保存RSP数据的指针，如果不需要保存，则置为NULL，此指针会传递给rsp_cback函数
 * @param[in] timeout 等待超时时间
 * @param[in] ignore_rsp_status 是否忽略RSP的状态，如果为true则不会检查RSP的状态
 * @param[inout] p_ntf_wait_list 设置的NTF等待队列的指针
 * @param[in] ntf_wait_list_size NTF等待列表的大小
 * @param[in] ntf_wait_cback NTF等待回调函数，在获取到RSP后和没接收到一次NTF后都会调用此函数，此回调函数返回true后会终止等待NTF
 * @return 如果设置了NTF等待列表则返回ntf_wait_cback中返回的状态，反之返回RSP接收状态
*/
tNCI_STATUS nci_tp_send_nci_get_rsp_wait_ntf(tNCI_BUF *cmd, tNCI_BUF *rsp, uint32_t timeout, bool ignore_rsp_status,
                                            tNCI_WAIT_BUF *p_ntf_wait_list, uint8_t ntf_wait_list_size, tNCI_NTF_WAIT_CBACK ntf_wait_cback);
/**
 * @brief 默认的NTF等待回调函数实现，只要p_ntf_wait_list中有一个接收到就返回true终止其他的等待
 *
 * @param cmd 发送的NCI指令头
 * @param rsp 接收到的NCI RSP
 * @param p_ntf_wait_list NTF等待列表的指针
 * @param ntf_wait_list_size NTF等待列表的大小
 * @param p_return_status 用于输出等待到的NTF的状态
 *
 * @return 当p_ntf_wait_list中有一个NTF接收到，则返回true，否则返回false
 */
bool nci_tp_default_ntf_wait_cback(tNCI_HEAD cmd, tNCI_BUF *rsp, tNCI_WAIT_BUF *p_ntf_wait_list, uint8_t ntf_wait_list_size, tNCI_STATUS *p_return_status);
/**
 * @brief 向指定的Data通道传输数据并等待返回
 *
 * @param channel 发送数据的通道
 * @param cmd 需要发送的数据
 * @param rsp 用于保存返回数据的指针
 * @param timeout 等待超时时间
 * @return NCI_STATUS_OK: 发送成功且获取到RSP
 *         NCI_STATUS_EXT_CMD_SEND_FAILED: 发送失败
*/
tNCI_STATUS nci_tp_send_data(tNCI_DATA_CHANNEL *channel, tNCI_BUF *cmd, tNCI_BUF *rsp, uint32_t timeout);

/**
 * @brief 异步发送Data数据，不等待RSP
 *
 * @param channel 发送数据的通道
 * @param data 待发送的数据
 * @param timeout 等待credit的超时时间
 *
 * @return NCI_STATUS_OK: 发送成功，其他情况返回对应错误码
 */
tNCI_STATUS nci_tp_send_data_async(tNCI_DATA_CHANNEL *channel, tNCI_BUF *data, uint32_t timeout);

/**
 * @brief 初始化NFC功能
 *
 * @return NCI_STATUS_OK: 初始化成功，其他情况返回对应错误码
 */
tNCI_STATUS nci_tp_core_initialized();

#endif /* _NCI_TRANSPORT_H_ */
